package qc.module.qms.dps.job;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import qc.common.core.enums.qms.QmsDataFlowOperateTypeEnum;
import qc.common.core.enums.qms.QmsPointTimeSegmentEnum;
import qc.common.core.utils.IdentifierUtil;
import qc.common.core.utils.LocalDateTimeUtil;
import qc.module.qms.algorithm.NumericCalc.dto.QmsNumericCalcUseMethod;
import qc.module.qms.dto.calc.QmsPointDataCalcJudgeResultDto;
import qc.module.qms.dto.calc.QmsPointDataCalcSaveResultDto;
import qc.module.qms.entity.QmsPoint;
import qc.module.qms.service.QmsBasicConfigCacheGetService;
import qc.module.qms.service.calc.QmsNumericCalcGetService;
import qc.module.qms.service.pointdata.QmsPointDataCalcService;
import qc.module.qms.service.pointdata.QmsPointDataLatestService;
import tech.powerjob.worker.core.processor.ProcessResult;
import tech.powerjob.worker.core.processor.TaskContext;
import tech.powerjob.worker.core.processor.sdk.BasicProcessor;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 定时计算点号数据Processor
 *
 * @author QuCheng Tech
 * @since 2025/10/6
 */
@Component
public class CalcPointDataJobProcessor implements BasicProcessor {
    private static final Logger logger = LoggerFactory.getLogger(CalcPointDataJobProcessor.class);

    @Autowired
    private QmsBasicConfigCacheGetService basicConfigCacheGetService;

    @Autowired
    private QmsPointDataCalcService pointDataCalcService;

    @Autowired
    private QmsNumericCalcGetService numericCalcGetService;

    @Autowired
    private QmsPointDataLatestService pointDataLatestService;

    @Override
    public ProcessResult process(TaskContext taskContext) {
        /**
         * 点号数据处理逻辑及控制
         * 通过PowerJob控制任务的频率和触发时间，通过任务中的参数指定任务的计算点号时段类型（一个任务对应一种时段类型）
         * 每次触发任务处理时均对时段类型中的所有点号进行一次处理，不管是否有相同的任务
         * 配置建议：小时时段类型配置为每个小时整点后2-3分钟触发1次；日时段类型配置每天0点和8点后2-5分钟触发1次；
         */
        logger.debug("process taskContext.getJobParams=" + taskContext.getJobParams());

        String jobParams = taskContext.getJobParams();
        if (StringUtils.isBlank(jobParams)) {
            //返回ProcessResult中为false时会导致Powerjob一直重试，因此返回结果中设置为true
            //return new ProcessResult(false, "任务参数未设置，请在任务参数中指定一个时段类型。");
            return new ProcessResult(true, "任务参数未设置，请在任务参数中指定一个时段类型。");
        } else {
            //时段类型字符串转换为int，后继可以扩展任务参数为json格式
            try {
                int intValue = Integer.parseInt(jobParams);
                QmsPointTimeSegmentEnum tmseg = QmsPointTimeSegmentEnum.getQmsPointTimeSegmentEnum(intValue);
                if (tmseg == QmsPointTimeSegmentEnum.UN_DEFINE) {
                    return new ProcessResult(true, "任务参数设置错误，无法转换为对应的时段类型。");
                } else if (tmseg == QmsPointTimeSegmentEnum.REAL || tmseg == QmsPointTimeSegmentEnum.MINUTE) {
                    return new ProcessResult(true, "任务参数设置错误，实时和分钟时段类型不需要进行定时点号计算。");
                } else {
                    LocalDateTime now = LocalDateTimeUtil.getNow();
                    //指定optype为定时点号计算
                    QmsDataFlowOperateTypeEnum optype = QmsDataFlowOperateTypeEnum.CALC_POINT_DATA_BY_TIMER;
                    List<QmsPoint> points = basicConfigCacheGetService.getTimeSegmentPoints(tmseg);
                    if (points != null && points.size() > 0x0) {
                        logger.debug("process 定时进行点号数据计算，计算时段类型[" + tmseg + "]，共有点号数量[" + points.size() + "]个");
                        //按计算顺序进行排序后遍历
                        List<QmsPoint> sortedPoints = points.stream().sorted(Comparator.comparingInt(QmsPoint::getCalcodr)).collect(Collectors.toList());
                        for (QmsPoint point : sortedPoints) {
                            String pointid = point.getPointid();
                            //需要先判断点号是否有计算方法，如果没有计算方法不进行计算；如果不先判断是否有计算方法会在计算中生成错误日志
                            QmsNumericCalcUseMethod calcMethod = numericCalcGetService.getPointValidCalcUseMethod(point, tmseg);
                            if (calcMethod == null) {
                                logger.warn("计算点号[" + pointid + "]，时段类型[" + tmseg + "]，无有效的计算方法，不进行定时计算");
                            } else {
                                QmsPointDataCalcJudgeResultDto judgeResult = numericCalcGetService.getTimerJobCalcPointDataJudgeResult(point, tmseg, calcMethod, now);
                                if (judgeResult == null) {
                                    logger.warn("计算点号[" + pointid + "]，时段类型[" + tmseg + "]，判断本次计算时段结果为空，不进行定时计算");
                                } else {
                                    if (judgeResult.isNeedCalc() == false) {
                                        //不需要计算
                                        logger.info(judgeResult.getMsg());
                                    } else {
                                        //需要计算
                                        logger.info(judgeResult.getMsg());
                                        //对每个点号计算生成一个全局的流程ID，同时也作为节点ID
                                        String flowid = IdentifierUtil.simpleUUID();
                                        //调用计算方法，在pointDataCalcService.calc方法中已经完成日志记录、流程日志消息发送、原始数据处理标记修改
                                        //此处可以不对处理结果进行判断和输出显示
                                        QmsPointDataCalcSaveResultDto calcSaveResultDto = pointDataCalcService.calcPointDatas(point, tmseg, calcMethod, judgeResult.getCalcBeginPeriodTime(), judgeResult.getCalcEndPeriodTime()
                                                , optype, false, flowid, flowid);

                                        //计算完成后更新点号的最新定时计算时段
                                        pointDataLatestService.updateCalcDataTime(pointid, tmseg, judgeResult.getCalcEndPeriodTime(), false);
                                    }
                                }
                            }
                        }
                    }

                    return new ProcessResult(true, "成功");
                }
            } catch (NumberFormatException e) {
                return new ProcessResult(true, "任务参数设置错误，无法转换为整数。");
            }
        }
    }
}